package net.aspw.client.features.module.impl.exploit

import net.aspw.client.event.EventTarget
import net.aspw.client.event.PacketEvent
import net.aspw.client.event.UpdateEvent
import net.aspw.client.features.module.Module
import net.aspw.client.features.module.ModuleCategory
import net.aspw.client.features.module.ModuleInfo
import net.aspw.client.utils.timer.TimeUtils
import net.aspw.client.value.IntegerValue
import net.minecraft.network.Packet
import net.minecraft.network.play.client.C00PacketKeepAlive
import net.minecraft.network.play.client.C16PacketClientStatus

@ModuleInfo(name = "PingSpoofer", spacedName = "Ping Spoofer", category = ModuleCategory.EXPLOIT)
class PingSpoofer : Module() {
    private val packetsMap = HashMap<Packet<*>, Long>()
    override fun onDisable() {
        packetsMap.clear()
    }

    private val maxDelayValue: IntegerValue = object : IntegerValue("MaxDelay", 250, 0, 5000, "ms") {
        override fun onChanged(oldValue: Int, newValue: Int) {
            val minDelayValue = minDelayValue.get()
            if (minDelayValue > newValue) set(minDelayValue)
        }
    }

    @EventTarget
    fun onPacket(event: PacketEvent) {
        if (mc.isIntegratedServerRunning) return
        val packet = event.packet
        if ((packet is C00PacketKeepAlive || packet is C16PacketClientStatus) && !(mc.thePlayer.isDead || mc.thePlayer.health <= 0) && !packetsMap.containsKey(
                packet
            )
        ) {
            event.cancelEvent()
            synchronized(packetsMap) {
                packetsMap.put(
                    packet,
                    System.currentTimeMillis() + TimeUtils.randomDelay(minDelayValue.get(), maxDelayValue.get())
                )
            }
        }
    }

    @EventTarget(ignoreCondition = true)
    fun onUpdate(event: UpdateEvent?) {
        if (mc.isIntegratedServerRunning) return
        synchronized(packetsMap) {
            val iterator: MutableIterator<Map.Entry<Packet<*>, Long>> = packetsMap.entries.iterator()
            while (iterator.hasNext()) {
                val (key, value) = iterator.next()
                if (value < System.currentTimeMillis()) {
                    mc.netHandler.addToSendQueue(key)
                    iterator.remove()
                }
            }
        }
    }

    private val minDelayValue: IntegerValue = object : IntegerValue("MinDelay", 200, 0, 5000, "ms") {
        override fun onChanged(oldValue: Int, newValue: Int) {
            val maxDelayValue = maxDelayValue.get()
            if (maxDelayValue < newValue) set(maxDelayValue)
        }
    }
}